package common

import (
	"encoding/xml"
	"time"

	"github.com/gin-gonic/gin"
)

// ErrorXML represents S3-compatible XML error response
type ErrorXML struct {
	XMLName xml.Name `xml:"Error"`
	Code    string   `xml:"Code"`
	Message string   `xml:"Message"`
}

// WriteS3Error writes S3-compatible XML error based on our utils.S3Error fields.
func WriteS3Error(c *gin.Context, status int, code, message string) {
	c.Header("Content-Type", "application/xml")
	c.Status(status)
	_ = xml.NewEncoder(c.Writer).Encode(ErrorXML{Code: code, Message: message})
}

// ListAllMyBucketsResult is S3-compatible bucket listing XML root
type ListAllMyBucketsResult struct {
	XMLName xml.Name                 `xml:"ListAllMyBucketsResult"`
	Buckets []ListAllMyBucketsBucket `xml:"Buckets>Bucket"`
}

type ListAllMyBucketsBucket struct {
	Name         string    `xml:"Name"`
	CreationDate time.Time `xml:"CreationDate"`
}

// ListBucketResult (V2) XML
type ListObjectsV2Result struct {
	XMLName               xml.Name              `xml:"ListBucketResult"`
	Name                  string                `xml:"Name"`
	Prefix                string                `xml:"Prefix"`
	Delimiter             string                `xml:"Delimiter,omitempty"`
	MaxKeys               int                   `xml:"MaxKeys"`
	KeyCount              int                   `xml:"KeyCount"`
	IsTruncated           bool                  `xml:"IsTruncated"`
	ContinuationToken     string                `xml:"ContinuationToken,omitempty"`
	NextContinuationToken string                `xml:"NextContinuationToken,omitempty"`
	Contents              []ListObjectV2Content `xml:"Contents"`
	CommonPrefixes        []ListCommonPrefix    `xml:"CommonPrefixes"`
}

type ListObjectV2Content struct {
	Key          string    `xml:"Key"`
	LastModified time.Time `xml:"LastModified"`
	ETag         string    `xml:"ETag"`
	Size         int64     `xml:"Size"`
}

type ListCommonPrefix struct {
	Prefix string `xml:"Prefix"`
}

// CopyObject
type CopyObjectResult struct {
	XMLName      xml.Name `xml:"CopyObjectResult"`
	ETag         string   `xml:"ETag"`
	LastModified string   `xml:"LastModified"`
}

// DeleteObjects (batch)
type DeleteRequest struct {
	XMLName xml.Name           `xml:"Delete"`
	Quiet   bool               `xml:"Quiet"`
	Objects []ObjectIdentifier `xml:"Object"`
}

type ObjectIdentifier struct {
	Key string `xml:"Key"`
}

type DeleteResult struct {
	XMLName xml.Name        `xml:"DeleteResult"`
	Deleted []DeletedObject `xml:"Deleted"`
	Errors  []DeleteError   `xml:"Error,omitempty"`
}

type DeletedObject struct {
	Key string `xml:"Key"`
}

type DeleteError struct {
	Key     string `xml:"Key"`
	Code    string `xml:"Code"`
	Message string `xml:"Message"`
}

// MPU: ListParts
type ListPartsResult struct {
	XMLName              xml.Name      `xml:"ListPartsResult"`
	Bucket               string        `xml:"Bucket"`
	Key                  string        `xml:"Key"`
	UploadID             string        `xml:"UploadId"`
	PartNumberMarker     int           `xml:"PartNumberMarker"`
	NextPartNumberMarker int           `xml:"NextPartNumberMarker,omitempty"`
	MaxParts             int           `xml:"MaxParts"`
	IsTruncated          bool          `xml:"IsTruncated"`
	Parts                []PartSummary `xml:"Part"`
}

type PartSummary struct {
	PartNumber   int       `xml:"PartNumber"`
	LastModified time.Time `xml:"LastModified"`
	ETag         string    `xml:"ETag"`
	Size         int64     `xml:"Size"`
}

// MPU: ListMultipartUploads
type ListMultipartUploadsResult struct {
	XMLName            xml.Name        `xml:"ListMultipartUploadsResult"`
	Bucket             string          `xml:"Bucket"`
	KeyMarker          string          `xml:"KeyMarker,omitempty"`
	UploadIdMarker     string          `xml:"UploadIdMarker,omitempty"`
	NextKeyMarker      string          `xml:"NextKeyMarker,omitempty"`
	NextUploadIdMarker string          `xml:"NextUploadIdMarker,omitempty"`
	MaxUploads         int             `xml:"MaxUploads"`
	IsTruncated        bool            `xml:"IsTruncated"`
	Uploads            []UploadSummary `xml:"Upload"`
}

type UploadSummary struct {
	Key       string    `xml:"Key"`
	UploadId  string    `xml:"UploadId"`
	Initiated time.Time `xml:"Initiated"`
}

// Lifecycle Configuration Types
type LifecycleConfiguration struct {
	XMLName xml.Name        `xml:"LifecycleConfiguration"`
	Rules   []LifecycleRule `xml:"Rule"`
}

type LifecycleRule struct {
	ID                             string                          `xml:"ID"`
	Status                         string                          `xml:"Status"`
	Filter                         *LifecycleFilter                `xml:"Filter,omitempty"`
	Expiration                     *LifecycleExpiration            `xml:"Expiration,omitempty"`
	NoncurrentVersionExpiration    *NoncurrentVersionExpiration    `xml:"NoncurrentVersionExpiration,omitempty"`
	NoncurrentVersionTransitions   []NoncurrentVersionTransition   `xml:"NoncurrentVersionTransition,omitempty"`
	Transitions                    []LifecycleTransition           `xml:"Transition,omitempty"`
	AbortIncompleteMultipartUpload *AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty"`
}

type LifecycleFilter struct {
	Prefix string `xml:"Prefix,omitempty"`
	Tag    *Tag   `xml:"Tag,omitempty"`
}

type Tag struct {
	Key   string `xml:"Key"`
	Value string `xml:"Value"`
}

type LifecycleExpiration struct {
	Days                      int    `xml:"Days,omitempty"`
	Date                      string `xml:"Date,omitempty"`
	ExpiredObjectDeleteMarker bool   `xml:"ExpiredObjectDeleteMarker,omitempty"`
}

type NoncurrentVersionExpiration struct {
	NoncurrentDays int `xml:"NoncurrentDays"`
}

type NoncurrentVersionTransition struct {
	NoncurrentDays int    `xml:"NoncurrentDays"`
	StorageClass   string `xml:"StorageClass"`
}

type LifecycleTransition struct {
	Days         int    `xml:"Days,omitempty"`
	Date         string `xml:"Date,omitempty"`
	StorageClass string `xml:"StorageClass"`
}

type AbortIncompleteMultipartUpload struct {
	DaysAfterInitiation int `xml:"DaysAfterInitiation"`
}
